package com.example.blog_system_ssm.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.example.blog_system_ssm.common.*;
import com.example.blog_system_ssm.component.RedisUtil;
import com.example.blog_system_ssm.model.UserInfo;
import com.example.blog_system_ssm.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private SensitiveWordUtil sensitiveWordUtil;
    @RequestMapping("/reg")
    public Object reg(HttpServletRequest request, String username, String password,String timeStamp){
        //非空校验
        if(!StringUtils.hasLength(username)||!StringUtils.hasLength(password)){
            return AjaxResult.fail(-1,"参数非法");
        }
        //判断用户名是否存在敏感词
        if(sensitiveWordUtil.contains(username)){
            return AjaxResult.fail(-1,"用户名存在敏感词");
        }
        //校验验证码是否正确
        String verCode= (String) redisTemplate.opsForValue().get(Constant.LOGIN_KAPTCHA_KEY+timeStamp);
        String rightCode = request.getParameter("rightCode");
        //判断验证码是否正确或者是否为万能码
        if(!verCode.equals(rightCode)&&!Constant.UNIVERSAL_KAPTCHA_CODE.equals(rightCode)){
            //验证码错误
            return AjaxResult.fail(200,"验证码错误",0);
        }
        //新增用户
        int result=userService.add(username, SecurityUtil.encrypt(password));//进行加盐操作
        if(result==1){
            return AjaxResult.success("添加用户成功",1);
        }else if(result==0){
            return AjaxResult.fail(-1,"添加用户失败");
        }else {
            return AjaxResult.fail(-1,"用户名存在重复，请重试");
        }
    }

    @RequestMapping("/login")
    public Object login(HttpServletRequest request,String username, String password,String timeStamp){
        String verCode= (String) redisTemplate.opsForValue().get(Constant.LOGIN_KAPTCHA_KEY+timeStamp);//服务器生成的验证码
        String rightCode = request.getParameter("rightCode");//客户端输入的验证码
        //非空校验
        if(!StringUtils.hasLength(username)||!StringUtils.hasLength(password)||!StringUtils.hasLength(rightCode)){
            return AjaxResult.success("部分参数为空",0);
        }
        //重复登录校验
        String checkToken=request.getHeader("authorization");
        String key=Constant.LOGIN_USER_KEY+checkToken;
        //判断验证码是否错误
        boolean checkKaptchaWrong = !verCode.equals(rightCode) && !Constant.UNIVERSAL_KAPTCHA_CODE.equals(rightCode);
        boolean checkKaptchaRight = verCode.equals(rightCode) || Constant.UNIVERSAL_KAPTCHA_CODE.equals(rightCode);
        if(StrUtil.isNotBlank(checkToken)){
            //根据token从redis获取数据
            Map<Object,Object> userMap=redisTemplate.opsForHash().entries(key);
            //判断查询的用户信息是否与输入的一致
            if(MapUtil.isNotEmpty(userMap)){
                UserInfo checkUser=BeanUtil.fillBeanWithMap(userMap,new UserInfo(),false);
                boolean checkResult=SecurityUtil.decrypt(password,checkUser.getPassword());
                if(username.equals(checkUser.getUsername())&&checkResult&&(checkKaptchaRight)){
                    return AjaxResult.success("重复登录",-2);
                }else if(username.equals(checkUser.getUsername())&&(!checkResult&& checkKaptchaRight)){
                    //此处如果用户名与redis中查询到的不相同说明可能是新用户登录
                    //执行下面正常登录的逻辑
                    //所以此处判断重复登录输入的用户名一定与redis查询到的相同
                    return AjaxResult.success("用户名或密码错误",-1);
                } else if(username.equals(checkUser.getUsername())&&checkResult&& checkKaptchaWrong){
                    return AjaxResult.success("验证码错误",0);
                }
            }
        }

        //数据库进行查询操作
        UserInfo userInfo=userService.getUserByName(username);
        if(userInfo==null||userInfo.getId()<=0){
            //参数错误
            return AjaxResult.success("用户名或密码错误",-1);
        }else{
            //判断登录是否有效
            boolean result=SecurityUtil.decrypt(password,userInfo.getPassword());
            //登录错误次数
            Integer errorCount=(Integer) redisTemplate.opsForValue().get(Constant.LOGIN_USER_ERROR+userInfo.getId());
            //账户是否被冻结
            if(errorCount!=null&&errorCount>=5){
                Long freezeTime=redisTemplate.getExpire(Constant.LOGIN_USER_ERROR+userInfo.getId(),TimeUnit.MINUTES);
                return AjaxResult.success("登录错误次数过多，账户已被冻结"+freezeTime+"分钟",-3);
            }
            //校验验证码及密码是否正确
            if(result&& checkKaptchaRight){
                //通过验证则将userinfo储存到redis中
                String token= UUID.randomUUID().toString(true);
                String tokenKey=Constant.LOGIN_USER_KEY+token;
                Map<String,Object> userMap= BeanUtil.beanToMap(userInfo);
                redisTemplate.opsForHash().putAll(tokenKey,userMap);
                //设置token有效期
                redisTemplate.expire(tokenKey,30, TimeUnit.MINUTES);
                return AjaxResult.success(token,1);
            }else if(checkKaptchaWrong){
                return AjaxResult.success("验证码错误",0);
            }else{
                if(errorCount==null){
                    redisTemplate.opsForValue().set(Constant.LOGIN_USER_ERROR+userInfo.getId(),1,Constant.LOGIN_USER_FREEZE,TimeUnit.MINUTES);
                }else if(errorCount<5){
                    redisTemplate.opsForValue().increment(Constant.LOGIN_USER_ERROR+userInfo.getId());
                }
                errorCount=(Integer) redisTemplate.opsForValue().get(Constant.LOGIN_USER_ERROR+userInfo.getId());
                if(errorCount>=5){
                    Long freezeTime=redisTemplate.getExpire(Constant.LOGIN_USER_ERROR+userInfo.getId(),TimeUnit.MINUTES);
                    return AjaxResult.success("登录错误次数过多，账户已被冻结"+freezeTime+"分钟",-3);
                }
                return AjaxResult.success("用户名或密码错误",-1);
            }
        }
    }

    @RequestMapping("/myinfo")
    public UserInfo myInfo() {
        return UserThreadLocal.get();
    }

    @RequestMapping("/logout")
    public boolean logout(HttpServletRequest request){
        String token=request.getHeader("authorization");
        String key=Constant.LOGIN_USER_KEY+token;
        //由于未传指定列，所以不能使用 redisTemplate.opsForHash().delete(key)
        //否则会报 Fields must not be empty
        redisTemplate.delete(key);
        UserThreadLocal.remove();
        return true;
    }

    @RequestMapping("/myinfobyuid")
    public UserInfo myInfoByUid(Long uid){
        if(uid>0){
            UserInfo userinfo=userService.myInfoByUid(uid);
            //用户信息脱敏
            userinfo.setPassword("");
            return userinfo;
        }
        return null;
    }
}
